#ifndef _SDB_THREAD_H_
#define _SDB_THREAD_H_

/* 
 * Spinneret - Semi-Structured Database Engine
 * Copyright (c) 2009 Tom Bradford <spinneretdb.org>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a 
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * Wraps and abstracts basic threading constructs such as threads 
 * and mutexes.  You'll notice that only the base minimum 
 * functionality is exposed.  This is for purposes of both ease
 * of use and portability.
 */

#include <stdbool.h>
#include <stdlib.h>

#include "utils/mem.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus


/** Incomplete type for Thread instances */
typedef struct sdb_thread_t sdb_thread_t;

/** Incomplete type for Mutex instances */
typedef struct sdb_mutex_t sdb_mutex_t;

/** Function type for Thread execution and cleanup */
typedef bool sdb_thread_function_t(sdb_thread_t* thread, void* context);
                                             
/** Create an Thread instance */
sdb_thread_t* sdb_thread_new(sdb_mem_t* mem);

/** Initializes the most common attributes of a Thread instance */
sdb_thread_t* sdb_thread_init(sdb_thread_t* thread,
                              sdb_thread_function_t* runnableFunction,
                              sdb_thread_function_t* cleanupFunction,
                              void* context);

/** Sets the Runnable function for the Thread instance */
void sdb_thread_setRunnableFunction(sdb_thread_t* thread, 
                                    sdb_thread_function_t* runnableFunction);

/** Returns the Runnable function for the Thread instance */
sdb_thread_function_t* sdb_thread_getRunnableFunction(sdb_thread_t* thread);

/** Sets the Cleanup function for the Thread instance */
void sdb_thread_setCleanupFunction(sdb_thread_t* thread, 
                                   sdb_thread_function_t* cleanupFunction);

/** Returns the Cleanup function for the Thread instance */
sdb_thread_function_t* sdb_thread_getCleanupFunction(sdb_thread_t* thread);

/** Sets the Context for the Thread instance */
void sdb_thread_setContext(sdb_thread_t* thread, void* context);

/** Returns the Context for the Thread instance */
void* sdb_thread_getContext(sdb_thread_t* thread);

/** Starts The Thread instance's Runnable function */
bool sdb_thread_start(sdb_thread_t* thread);

/** Stops the Thread instance's execution */
bool sdb_thread_stop(sdb_thread_t* thread);

/** Joins a Thread instance's execution (waits for Thread to end) */
bool sdb_thread_join(sdb_thread_t* thread);

/** Returns whether or not the Thread insance is executing */
bool sdb_thread_isRunning(sdb_thread_t* thread);

/** Create a Mutex instance */
sdb_mutex_t* sdb_mutex_new(sdb_mem_t* mem);

/** Instructs the current Thread to wait until the Mutex is notified */
void sdb_mutex_wait(sdb_mutex_t* mutex);

/** Notifies a Thread that the Mutex instance is able to proceed */
void sdb_mutex_notify(sdb_mutex_t* mutex);

/** Notifies all Threads that the Mutex instance is able to proceed */
void sdb_mutex_notifyAll(sdb_mutex_t* mutex);

/** Locks the Mutex instance.  Blocks if locked already */
bool sdb_mutex_lock(sdb_mutex_t* mutex);

/** Attempts a Lock on the Mutex instance.  Fails if locked already */
bool sdb_mutex_tryLock(sdb_mutex_t* mutex);

/** Unlocks the Mutex instance */
bool sdb_mutex_unlock(sdb_mutex_t* mutex);


#ifdef __cplusplus
}
#endif // __cplusplus

#endif // _SDB_THREAD_H_
